#include "shade_model.h"

#include "../math/lighting.h"

#include "material.h"
#include "light.h"

namespace ray_tracing
{
	
	vec3f shade(ray_tracing::scene_t* scene, const ray3f& ray, uint32_t recursion_depth)
	{
		vec3f color = vec3fc(0,0,0);

		static const float margin = 0.01f;
		static const uint32_t max_depth_recursion = 6;

		if(recursion_depth > max_depth_recursion)
			return color;

		camera_t* camera = scene->get_rendering_camera();

		collision::collision_info_t coll_info = scene->intersect_with(ray, hit_param::last_hit);

		scene_object_t* intersected_object = static_cast<scene_object_t*>(coll_info.user_data);
		if(intersected_object)
		{
			material_t* material = intersected_object->material;

			if(material)
			{
				auto& lights = scene->get_lights();

				vec3f N = coll_info.normal;

				color += material->ambient_color;

				for(light_t* light : lights)
				{
					ray3f obj_light_ray = create_ray_between_2_points(coll_info.pos, light->origin, margin);

					// if there is no intersection between intersected surface and light, then compute color that light contributes to
					// intersected surface
					if(scene->intersect_with(obj_light_ray, hit_param::first_hit).user_data == nullptr)
					{	
						vec3f L = normalize(light->origin - coll_info.pos);

						color += material->diffuse_color * lighting::lambert(N,L);
				
						color += material->specular_color * lighting::phong(N,L,camera->eye,coll_info.pos,
							material->specular_power);

						color = mul_vec(color, light->L);
					}
				}

				// compute reflection color
				ray3f reflected_ray = create_reflected_ray(ray, coll_info.pos, coll_info.normal, margin);
				vec3f reflection_color = shade(scene, reflected_ray, recursion_depth + 1);

				//blend reflected color with main color
				color = lerp(color, reflection_color, material->reflection_contribution);
		
				float sign = coll_info.status == collision::collision_status::inside ? -1.f : 1.f;

				ray3f refraction_ray = create_refraction_ray(ray, coll_info.pos, N * sign,
					material->refraction_index, margin);

				if(!e_null_ray(refraction_ray))
				{
					vec3f refraction_color = shade(scene, refraction_ray, recursion_depth + 1);

					color = lerp(color, refraction_color, material->refraction_contribution);
				}
			}
		}

		return color;
	}
}